/*
 * Copyright 2013 Agustina Martinez-Garcia

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package uk.da.dext.genxml;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import uk.da.dext.datastructs.CodeStruct;

public class CodeManagement implements ElementsManagement {
	private static final String FIELDS_SEPARATOR = ";";

	/**
	 * Fedora generated PID for the document referenced by this code set, just used once when creating the partial map
	 */
	private String currentDocumentPID;
	
	/**
	 * 
	 */
	private String currentDocumentXmlId;
	
	/**
	 * Codes labels for generating Qudex Instance, pairs value/label
	 */
	private Map<String, String> codesMap;
	/**
	 * 
	 */
	private List<CodeStruct> codesList;
	/**
	 * @param currentDocumentPID the currentDocuementPID to set
	 */
	public void setCurrentDocumentPID(String currentDocumentPID) {
		this.currentDocumentPID = currentDocumentPID;
	}
	/**
	 * @return the currentDocumentPID
	 */
	public String getCurrentDocumentPID() {
		return currentDocumentPID;
	}
	/**
	 * @param currentDocumentXmlId the currentDocumentXmlId to set
	 */
	public void setCurrentDocumentXmlId(String currentDocumentXmlId) {
		this.currentDocumentXmlId = currentDocumentXmlId;
	}
	/**
	 * @return the currentDocumentXmlId
	 */
	public String getCurrentDocumentXmlId() {
		return currentDocumentXmlId;
	}
	/**
	 * Sets the array of codes
	 * @param codesList
	 */
	public void setCodesList(List<CodeStruct> codesList) {
		this.codesList = codesList;
	}
	/**
	 * Gets the array of codes
	 * @return codesList
	 */
	public List<CodeStruct> getCodesList() {
		return codesList;
	}
	
	/**
	 * Constructor
	 */
	public CodeManagement() {
		this.codesList = new ArrayList<CodeStruct>();
		this.currentDocumentPID = "";
		this.currentDocumentXmlId = "";
		this.codesMap = new HashMap<String, String>();
	}

	/**
	 * Finds a particular code in the array of codes by label value
	 * @param name display label of code to find
	 * @return code object if found, null otherwise
	 */
	public CodeStruct findElementByLabel(String name) {
		for (CodeStruct code : this.codesList) {
			if (code.getCodeLabel().equalsIgnoreCase(name)) {
				return code;
			}
		}
		//New category to add
		return null;
	}
	/**
	 * Finds a particular code in the array of codes by display-label value
	 * @param name display label of code to find
	 * @return category object if found, null otherwise
	 */
	public CodeStruct findElementByDisplayLabel(String name) {
		for (CodeStruct code : this.codesList) {
			if (code.getCodeDisplayLabel().equalsIgnoreCase(name)) {
				return code;
			}
		}
		//New category to add
		return null;
	}
	/**
	 * Clears the list of codes
	 */
	public void clearList() {
		for (CodeStruct code : this.codesList) {
			code.clearCodeLists();
		}
		this.codesList.clear();
		this.codesMap.clear();
	}
	/**
	 * 
	 * @param codesSpreadsheet list of codes extracted from the QuDEx spreadsheet
	 */
	public void constructListOfElements(String language) {
		for (String code : this.codesMap.keySet()) {
			processCode(code, this.codesMap.get(code).toString(), language);
		}
		this.codesMap.clear();
	}
	/**
	 * 
	 * @param codeLabel
	 * @param codeDisplayLabel
	 * @param generatedDocID
	 * @return
	 */
	private String processCode(String codeLabel, String codeDisplayLabel, String language) {
		CodeStruct auxCode = this.findElementByLabel(codeLabel);
		boolean isNewCode = false;
		
		if (auxCode == null) {
			auxCode = new CodeStruct();
			isNewCode = true;
			auxCode.setCodeLabel(codeLabel);
			auxCode.setCodeDisplayLabel(codeDisplayLabel);
			auxCode.setCodeXmlId(QudexManagement.generateID());
			auxCode.setCodeLanguage(language);
		}
		//Add current documentRef Fedora PID
		auxCode.getDocumentRefs().add(this.currentDocumentPID);
		//Add generated XMLID for the Fedora PID
		auxCode.getDocumentRefsXmlIds().add(this.currentDocumentXmlId);
		
		//New code not present
		if (isNewCode)
			this.codesList.add(auxCode);
		return  "";
	}
	
	/**
	 * Given a document Fedora Pid returns the generated XML-ID associated with it
	 * @param codeDisplayLabel current code display label
	 * @param documentPid fedora document pid to search for
	 * @return the document xml-id, null if not found
	 */
	public String getDocumentXmlId(String codeDisplayLabel, String documentPid) {
		
		CodeStruct auxCode = this.findElementByDisplayLabel(codeDisplayLabel);
		int i = 0;
		if (auxCode != null) {
			for (String document : auxCode.getDocumentRefs()) {
				if (document.equalsIgnoreCase(documentPid)) {
					return auxCode.getDocumentRefsXmlIds().get(i);
				}
				i++;
			}
			return null;
		} else return null;
	}
	/**
	 * Obtains the XML id of a given document by fedora PID
	 * @param documentPid fedora PID of the document to search
	 * @return xml id of the searched document
	 */
	public String searchDocumentIds(String documentPid) {
		for (CodeStruct code : this.codesList) {
			String documentXmlId = getDocumentXmlId(code.getCodeDisplayLabel(), documentPid);
			if (documentXmlId != null)
				return documentXmlId;
		}
		return null;
	}

	public List<?> getElementsList() {
	    return this.codesList;
	}
	
	 /**
	     * Generates the list of CodeStruct instances from the data parsed in the
	     * spreadsheet
	     * 
	     * @param valueCode
	     *            element in the spreadsheet labeled 'value_code'
	     * @param labelCode
	     *            element in the spreadsheet labeled 'label_code'
	     * @return true if operation successful, false otherwise
	     */
	    public boolean generateElementsMap(String valueCode, String labelCode) {
		String[] arrayCodeLabel = valueCode.split(FIELDS_SEPARATOR);
		String[] arrayCodeDisplayLabel = labelCode
			.split(FIELDS_SEPARATOR);
		if (arrayCodeLabel.length != arrayCodeDisplayLabel.length)
		    return false;
		for (int i = 0; i < arrayCodeLabel.length; i++) {
		    this.codesMap.put(arrayCodeLabel[i], arrayCodeDisplayLabel[i]);
		}
		return true;

	    }
	public Map<?, ?> getElementsMap() {
	    return this.codesMap;
	}
	@SuppressWarnings("unchecked")
	public void setElementsMap(Map<?, ?> map) {
	    this.codesMap = (Map<String, String>) map;
	}
	@SuppressWarnings("unchecked")
	public void setElementsList(List<?> ellist) {
		this.setCodesList((List<CodeStruct>) ellist);
	}
}
